﻿using System.Collections.Generic;
using System.Linq;
using System.Windows;
using JelleDruyts.Windows;
using JelleDruyts.Windows.ObjectModel;
using Schedulr.Infrastructure;
using Schedulr.Models;
using Schedulr.Providers;

namespace Schedulr.ViewModels
{
    /// <summary>
    /// The view model for the details panel of a selected picture or aggregation of multiple pictures.
    /// </summary>
    public class PictureDetailsViewModel : ObservableObject
    {
        #region Properties

        /// <summary>
        /// Gets the account.
        /// </summary>
        private Account Account { get; set; }

        /// <summary>
        /// Gets the informational message.
        /// </summary>
        public string InfoMessage { get; private set; }

        /// <summary>
        /// Gets the picture to display.
        /// </summary>
        public Picture Picture { get; private set; }

        /// <summary>
        /// Gets the visibility of the details panel.
        /// </summary>
        public Visibility DetailsPanelVisibility { get; private set; }

        /// <summary>
        /// Gets a value that determines if the details panel is visible.
        /// </summary>
        public bool DetailsPanelVisible { get; private set; }

        /// <summary>
        /// Gets the visibility of the information message.
        /// </summary>
        public Visibility InfoMessageVisibility { get; private set; }

        /// <summary>
        /// Gets the visibility of the file details.
        /// </summary>
        public Visibility FileDetailsVisibility { get; private set; }

        /// <summary>
        /// Gets the label for the tags input control.
        /// </summary>
        public string TagsLabel { get; private set; }

        /// <summary>
        /// Gets the size of the file as a string.
        /// </summary>
        public string FileSizeDescription { get; private set; }

        /// <summary>
        /// Gets the visibility of the file size error.
        /// </summary>
        public Visibility FileSizeErrorVisibility { get; private set; }

        /// <summary>
        /// Gets the visibility of the online details.
        /// </summary>
        public Visibility OnlineDetailsVisibility { get; private set; }

        /// <summary>
        /// Gets a value that determines if the picture details should be read-only.
        /// </summary>
        public bool IsReadOnly { get; private set; }

        /// <summary>
        /// Gets a value that determines if the picture details should be editable.
        /// </summary>
        public bool IsEditable { get; private set; }

        #endregion

        #region Observable Properties

        /// <summary>
        /// Gets the Flickr Sets to be displayed.
        /// </summary>
        public FlickrCollectionList Sets
        {
            get { return this.GetValue(SetsProperty); }
            set { this.SetValue(SetsProperty, value); }
        }

        /// <summary>
        /// The definition for the <see cref="Sets"/> observable property.
        /// </summary>
        public static ObservableProperty<FlickrCollectionList> SetsProperty = new ObservableProperty<FlickrCollectionList, PictureDetailsViewModel>(o => o.Sets);

        /// <summary>
        /// Gets the Flickr Groups to be displayed.
        /// </summary>
        public FlickrCollectionList Groups
        {
            get { return this.GetValue(GroupsProperty); }
            set { this.SetValue(GroupsProperty, value); }
        }

        /// <summary>
        /// The definition for the <see cref="Groups"/> observable property.
        /// </summary>
        public static ObservableProperty<FlickrCollectionList> GroupsProperty = new ObservableProperty<FlickrCollectionList, PictureDetailsViewModel>(o => o.Groups);

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="PictureDetailsViewModel"/> class.
        /// </summary>
        /// <param name="account">The account.</param>
        /// <param name="pictures">The pictures.</param>
        /// <param name="infoMessageVisibility">The visibility of the information message.</param>
        /// <param name="fileDetailsVisibility">The visibility of the file name.</param>
        /// <param name="isReadOnly">A value that determines if the picture details should be read-only.</param>
        public PictureDetailsViewModel(Account account, IList<Picture> pictures, Visibility infoMessageVisibility, Visibility fileDetailsVisibility, bool isReadOnly)
        {
            Picture picture = null;
            var detailsPanelVisibility = Visibility.Collapsed;
            string infoMessage = null;
            string tagsLabel = null;
            var fileSizeErrorVisibility = Visibility.Collapsed;
            var onlineDetailsVisibility = Visibility.Collapsed;
            long fileSize = 0;
            if (pictures != null && pictures.Count > 0)
            {
                infoMessage = pictures.Count.ToCountString("picture", "Editing ");
                detailsPanelVisibility = Visibility.Visible;
                if (pictures.Count == 1)
                {
                    var onlyPicture = pictures[0];
                    picture = onlyPicture;
                    tagsLabel = "Ta_gs";
                    fileSize = picture.FileSize;
                    if (!Validator.IsPictureFileSizeValid(onlyPicture, account))
                    {
                        fileSizeErrorVisibility = Visibility.Visible;
                    }
                    onlineDetailsVisibility = (picture.DateUploaded.HasValue ? Visibility.Visible : Visibility.Collapsed);
                }
                else
                {
                    var aggregatePicture = new AggregatePicture(pictures);
                    picture = aggregatePicture;
                    fileSize = picture.FileSize;
                    tagsLabel = "Add the following ta_gs to all selected pictures";
                    fileDetailsVisibility = Visibility.Collapsed; // Always hide the file details for aggregate pictures.
                }
            }
            this.Account = account;
            this.Picture = picture;
            this.DetailsPanelVisibility = detailsPanelVisibility;
            this.DetailsPanelVisible = (this.DetailsPanelVisibility == Visibility.Visible);
            this.InfoMessage = infoMessage;
            this.InfoMessageVisibility = infoMessageVisibility;
            this.FileDetailsVisibility = fileDetailsVisibility;
            this.TagsLabel = tagsLabel;
            if (fileSize >= 0)
            {
                this.FileSizeDescription = fileSize.ToDisplayString();
            }
            this.FileSizeErrorVisibility = fileSizeErrorVisibility;
            this.OnlineDetailsVisibility = onlineDetailsVisibility;
            this.IsReadOnly = isReadOnly;
            this.IsEditable = !this.IsReadOnly;

            // Determine the sets and groups.
            UpdateSetsAndGroups();

            // When the User Info changes, update the sets and groups.
            if (this.Account != null)
            {
                this.Account.PropertyChanged += (sender, e) => { if (e.PropertyName == Account.UserInfoProperty.Name) { UpdateSetsAndGroups(); } };
            }
        }

        #endregion

        #region Helper Methods

        private void UpdateSetsAndGroups()
        {
            IList<FlickrCollectionListItem> setsData = null;
            IList<FlickrCollectionListItem> groupsData = null;

            if (this.Picture != null)
            {
                var aggregatePicture = this.Picture as AggregatePicture;
                if (aggregatePicture == null)
                {
                    setsData = this.Account.UserInfo.Sets.Select(s => new FlickrCollectionListItem(s, this.Picture.SetIds, this.Picture.SetIds.Contains(s.Id), PathProvider.PlaceHolderImagePathFlickrSet)).ToList();
                    groupsData = this.Account.UserInfo.Groups.Select(g => new FlickrCollectionListItem(g, this.Picture.GroupIds, this.Picture.GroupIds.Contains(g.Id), PathProvider.PlaceHolderImagePathFlickrGroup)).ToList();
                }
                else
                {
                    setsData = this.Account.UserInfo.Sets.Select(s => new FlickrCollectionListItem(s, aggregatePicture.SetIds, aggregatePicture.SetIdsContains(s.Id), PathProvider.PlaceHolderImagePathFlickrSet)).ToList();
                    groupsData = this.Account.UserInfo.Groups.Select(g => new FlickrCollectionListItem(g, aggregatePicture.GroupIds, aggregatePicture.GroupIdsContains(g.Id), PathProvider.PlaceHolderImagePathFlickrGroup)).ToList();
                }
            }

            this.Sets = new FlickrCollectionList(setsData, "Sets");
            this.Groups = new FlickrCollectionList(groupsData, "Groups");
        }

        #endregion
    }
}